package com.bootx.service.impl;

import com.bootx.common.CommonAttributes;
import com.bootx.entity.Config;
import com.bootx.entity.OpenAiConfig;
import com.bootx.entity.RedPackageInfo;
import com.bootx.pojo.BotResponse;
import com.bootx.predict.pojo.PredictPlugin;
import com.bootx.service.ConfigService;
import com.bootx.service.OpenAiConfigService;
import com.bootx.service.RedPackageInfoService;
import com.bootx.service.RedisService;
import com.bootx.util.JsonUtils;
import com.bootx.predict.pojo.RedPacketBatch;
import com.bootx.predict.pojo.PredictionResult;
import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.annotation.Resource;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.content.Media;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.MimeTypeUtils;

import java.math.BigDecimal;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class RedPackageInfoServiceImpl implements RedPackageInfoService {

    @Resource
    private ChatClient chatClient;
    @Resource
    private OpenAiConfigService openAiConfigService;
    @Resource
    private JdbcTemplate jdbcTemplate;
    @Resource
    private RedisService redisService;

    @Resource
    private List<PredictPlugin> predictPlugins = new ArrayList<PredictPlugin>();
    @Autowired
    private ConfigService configService;

    @Override
    public void create(Path path) {
        OpenAiConfig openAiConfig = openAiConfigService.find(1L);
        if (openAiConfig == null) {
            System.out.println("apiKey没有配置");
            return;
        }
        if (openAiConfig.getRemainCount() <= 0) {
            System.out.println("22222剩余次数没有了，请充值");
            return;
        }
        FileSystemResource resource = new FileSystemResource(path.toFile());
        UserMessage userMessage = UserMessage.builder()
                .text(CommonAttributes.PROMPT2)
                .media(new Media(MimeTypeUtils.IMAGE_PNG, resource)).build();
        try {
            String content = chatClient.prompt().messages(userMessage).call().content();
            System.out.println(content);
            RedPackageInfo redPackageInfo = JsonUtils.toObject(content, new TypeReference<RedPackageInfo>() {
            });
            if(redPackageInfo.getSn()!=null
                    && redPackageInfo.getSn()!=-1
                    && redPackageInfo.getRedPackageCount()!=null
                    && redPackageInfo.getRedPackageCount()!=-1
                    && redPackageInfo.getAmount()!=null
                    && redPackageInfo.getAmount().compareTo(BigDecimal.valueOf(-1L))>0
                    && redPackageInfo.getSn()<80000
            ){

                String s = redisService.get("redPackageInfo:maxSn");
                Long maxSn = null;
                try {
                    maxSn = Long.valueOf(s);
                }catch (Exception ignored){

                }
                //if(maxSn==null || redPackageInfo.getSn()-maxSn<5){
                    redPackageInfo.setSeconds(15);
                    redPackageInfo.setAmount(BigDecimal.valueOf(redPackageInfo.getRedPackageCount()).multiply(BigDecimal.valueOf(0.5)));
                    jdbcTemplate.update("insert into redpackageinfo(createdDate, lastModifiedDate, version, amount, redPackageCount, seconds, sn) value (NOW(),NOW(),0,?,?,?,?) on duplicate key update version=version+1,lastModifiedDate=NOW();",redPackageInfo.getAmount(),redPackageInfo.getRedPackageCount(),redPackageInfo.getSeconds(),redPackageInfo.getSn());
                    new Thread(()->{
                        int winCount = 0;
                        int loseCount = 0;
                        try {
                            winCount = Integer.parseInt(redisService.get("win"));
                        }catch (Exception ignored){}
                        try {
                            loseCount = Integer.parseInt(redisService.get("fail"));
                        }catch (Exception ignored){}
                        // 连续失败超过2次（包含），调整预测规则
                        if (loseCount<2){
                            updateIsRob(null);
                        }else{
                            updateIsRob2();
                        }
                    }).start();
                    redisService.set("redPackageInfo:maxSn",redPackageInfo.getSn()+"");
                //}
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            FileUtils.deleteQuietly(path.toFile());
        }
    }

    @Override
    public void updateIsRob(Integer count) {
        try {
            if(count==null){
                try {
                    count = Integer.parseInt(redisService.get("predictCount"));
                }catch (Exception e){
                    count = 50;
                }
            }

            Map<String, Object> map = jdbcTemplate.queryForMap("select id,sn, redPackageCount,amount,seconds from redpackageinfo order by sn desc limit 1;");
            OpenAiConfig openAiConfig = openAiConfigService.find(1L);
            if (openAiConfig == null) {
                System.out.println("apiKey没有配置");
                return;
            }
            if (openAiConfigService.getCount() <= 0) {
                System.out.println("33333剩余次数没有了，请充值");
                return;
            }
            // 再预测奇偶性
            SystemMessage systemMessage1 = new SystemMessage(CommonAttributes.PARSE_PROMPT2);
            UserMessage userMessage1 = new UserMessage("历史数据如下："+predict(count)+",下一轮红包个数："+map.get("redPackageCount")+"。下一轮红包总金额："+map.get("amount")+"。抢包持续时间："+map.get("seconds")+"秒。");
            openAiConfigService.updateCount(-2);
            String content1 = chatClient.prompt().messages(systemMessage1, userMessage1).call().content();
            System.out.println(content1);
            List<BotResponse> botResponses1 = JsonUtils.toObject(content1, new TypeReference<List<BotResponse>>() {
            });
            String s = redisService.get("predictType");
            BotResponse item = null;
            //  获取 position 最大的项
            Optional<BotResponse> maxPositionItem = botResponses1.stream()
                    .max(Comparator.comparingInt(BotResponse::getPosition));
            // 获取 position 最小的项
            Optional<BotResponse> minPositionItem = botResponses1.stream()
                    .min(Comparator.comparingInt(BotResponse::getPosition));
            //  获取 rate 最大的项
            Optional<BotResponse> maxRateItem = botResponses1.stream()
                    .max(Comparator.comparingDouble(BotResponse::getRate));
            // 获取 rate 最小的项
            Optional<BotResponse> minRateItem = botResponses1.stream()
                    .min(Comparator.comparingDouble(BotResponse::getRate));
            // 随机
            BotResponse randomItem = botResponses1.stream()
                    .skip(new Random().nextInt(botResponses1.size()))
                    .findFirst()
                    .orElse(null);

            if(StringUtils.equalsAnyIgnoreCase(s,"1")){
                // 序号最小
                item = minPositionItem.orElse(null);
            }else if(StringUtils.equalsAnyIgnoreCase(s,"2")){
                // 序号最大
                item = maxPositionItem.orElse(null);
            }else if(StringUtils.equalsAnyIgnoreCase(s,"3")){
                // 概率最小
                item =  minRateItem.orElse(null);
            }else if(StringUtils.equalsAnyIgnoreCase(s,"4")){
                // 概率最大
                item =  maxRateItem.orElse(null);
            }else{
                // 随机取一个
                item = randomItem;
            }

            System.out.println(JsonUtils.toJson(item));

            if(item==null){
                updateIsRob(null);
            }else {
                // 超过5秒钟，继续预测
                if(item.getOpenTime()>5000){
                    updateIsRob(50);
                }
                System.out.println(JsonUtils.toJson(item));
                if(item.getOpenTime()!=null){
                    redisService.set("stopTime", item.getOpenTime() + "");
                }
                redisService.set("index", item.getPosition() + "");
                jdbcTemplate.update("update redpackageinfo set isOdd=?,predictIndex=?,predictSeconds=?,version=version+1,lastModifiedDate=NOW() where id=? and sn=?",item.getIsOdd(),item.getPosition(),item.getOpenTime(),map.get("id"),map.get("sn"));

            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void updateIsRob2() {
        Config config = configService.find(1L);
        /**
         * [
         * basePredict：                                         {"index":1000,"total":5,"oddCount":4,"oddProbability":0.8,"avgOpenTime":10516}
         * bayesianPredict：                                     {"index":1000,"total":5,"oddCount":4,"oddProbability":0.7142857142857143,"avgOpenTime":10516}
         * chiSquareDeviationPredict：                           {"index":1000,"total":5,"oddCount":4,"oddProbability":0.8,"avgOpenTime":10516}
         * cyclePatternPredict：                                 {"index":1000,"total":5,"oddCount":4,"oddProbability":0.5,"avgOpenTime":10516}
         * exponentialSmoothingPredict：                         {"index":1000,"total":5,"oddCount":4,"oddProbability":0.8171200000000001,"avgOpenTime":10516}
         * globalPredict：                                       {"index":1000,"total":5,"oddCount":4,"oddProbability":0.8,"avgOpenTime":10516}
         * hotColdEffectStrategy：                               {"index":1000,"total":null,"oddCount":null,"oddProbability":0.85,"avgOpenTime":10516}
         * logisticRegressionPredict：                           {"index":1000,"total":5,"oddCount":4,"oddProbability":0.7211151780228631,"avgOpenTime":10516}
         * markovChainStrategy：                                 {"index":1000,"total":5,"oddCount":4,"oddProbability":0.6,"avgOpenTime":10516}
         * movingAvgStdPredict：                                 {"index":1000,"total":5,"oddCount":4,"oddProbability":0.99,"avgOpenTime":10516}
         * slidingWindowPredict：                                {"index":1000,"total":5,"oddCount":4,"oddProbability":0.8,"avgOpenTime":10516}
         * timeWeightedPredict：                                 {"index":1000,"total":5,"oddCount":4,"oddProbability":0.6309548641323808,"avgOpenTime":10516}
         * trendSlopePlugin：                                    {"index":1000,"total":5,"oddCount":4,"oddProbability":0.99,"avgOpenTime":10516}
         * weightedDecayPenaltyPredict：                         {"index":1000,"total":5,"oddCount":4,"oddProbability":0.7401798839684057,"avgOpenTime":10516}
         * weightedSmoothingPredict：                            {"index":1000,"total":5,"oddCount":4,"oddProbability":0.8709677419354839,"avgOpenTime":10516}
         */
        List<PredictPlugin> predictPluginList = predictPlugins.stream().filter(item -> StringUtils.equals(item.getName(), "basePredict")).toList();
        if(predictPluginList.isEmpty()){
            System.out.println("不存在该预测方法");
            return;
        }
        OpenAiConfig openAiConfig = openAiConfigService.find(1L);
        if (openAiConfig == null) {
            System.out.println("apiKey没有配置");
            return;
        }
        if (openAiConfigService.getCount() <= 0) {
            System.out.println("44444剩余次数没有了，请充值");
            return;
        }
        openAiConfigService.updateCount(-2);
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("SELECT * FROM (SELECT batchId,openInfo FROM redpackagestatistics ORDER BY batchId DESC LIMIT ?) AS recent ORDER BY batchId ASC;", config.getPredictionCount());
        List<RedPacketBatch> list = new ArrayList<>();
        maps.forEach(map -> {
            RedPacketBatch redPacketBatch = new RedPacketBatch();
            redPacketBatch.setBatchId(Long.valueOf(map.get("batchId").toString()));
            List<RedPacketBatch.RedPacketDetail> redPackets = JsonUtils.toObject(map.get("openInfo")+"", new TypeReference<List<RedPacketBatch.RedPacketDetail>>() {
            });
            redPackets.sort(Comparator.comparingInt(RedPacketBatch.RedPacketDetail::getIndex));
            List<RedPacketBatch.RedPacketDetail> collect = redPackets.stream()
                    .sorted(Comparator.comparingInt(rp -> -rp.getIndex()))
                    .limit(config.getWalletIndex())
                    .sorted(Comparator.comparingInt(RedPacketBatch.RedPacketDetail::getIndex))
                    .collect(Collectors.toList());

            if(collect.size()<config.getWalletIndex()){
                System.out.println("红包数不够");
                return;
            }

            // 去掉最后几个
            for(int i=0;i<config.getWalletIndex()-1;i++){
                collect.removeLast();
            }
            int newIndex = 1000;
            for (RedPacketBatch.RedPacketDetail rp : collect) {
                rp.setIndex(newIndex++);
            }
            redPacketBatch.setRedPackets(collect);
            list.add(redPacketBatch);
        });
        Set<Integer> indexs = new HashSet<>();
        indexs.add(1000);
        for (int i = 0; i < list.size(); i++) {
            indexs.add(1000+i);
        }
        List<PredictionResult> results = predictPluginList.getFirst().predict(list,indexs);
        // 提取出概率最大的一项
        PredictionResult best = results.stream()
                .max(Comparator.comparingDouble(PredictionResult::getOddProbability))
                .orElse(null);
        Map<String, Object> map = jdbcTemplate.queryForMap("select id,sn, redPackageCount,amount,seconds from redpackageinfo order by sn desc limit 1;");
        System.out.println(map.get("sn"));
        for (RedPacketBatch redPacketBatch : list) {
            System.out.println(redPacketBatch.getRedPackets().stream().map(RedPacketBatch.RedPacketDetail::getAmount).collect(Collectors.toList()));
        }
        System.out.println(JsonUtils.toJson(best));
        System.out.println("===================================================================================================================");
        assert best != null;
        if(best.getOddProbability()>0.5){
          redisService.set("bitType","1");
        }else{
            redisService.set("bitType","0");
        }
        redisService.set("stopTime", best.getAvgOpenTime() + "");
        redisService.set("index", best.getIndex() + "");
        jdbcTemplate.update("update redpackageinfo set predictData=?,predictResult=?, isOdd=?,predictIndex=?,predictSeconds=?,version=version+1,lastModifiedDate=NOW() where id=? and sn=?",JsonUtils.toJson(list),JsonUtils.toJson(results),best.getOddProbability()>0.5,best.getIndex(), best.getAvgOpenTime(),map.get("id"),map.get("sn"));
    }



    @Override
    public String predict(Integer count) {
        // 轮20250620212913(23): 3(0.36@2250),4(0.07@2375),6(0.09@2625),7(0.25@2750),10(1.09@3332),12(0.29@3664),16(1.01@5333),18(0.61@7500),19(0.83@10500),21(0.12@14500)
        List<String> data = new ArrayList<>();
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select batchId `round` from (select batchId from redpackagestatistics order by batchId desc limit ?) AS X order by X.batchId asc", count);
        maps.forEach(map -> {
            List<Map<String, Object>> records = jdbcTemplate.queryForList("select orders,ROUND(money,2) money,openTime, sum from redpackage where batchId=? order by orders asc ;",map.get("round"));
            if(records.size()>20){
                String s = "轮"+map.get("round")+"("+records.size()+")：";
                List<String> s1 = new ArrayList<>();
                for (int i = 0; i < records.size(); i++) {
                    Map<String, Object> record = records.get(i);
                    s1.add(record.get("orders")+"("+record.get("money")+"@"+record.get("openTime")+")");
                }
                data.add(s+StringUtils.join(s1,","));
            }
        });
        return StringUtils.join(data,"\n");
    }

    @Override
    public List<Map<String,Object>> predict2(Integer count) {
        List<String> data = new ArrayList<>();
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select batchId `roundId` from (select batchId from redpackagestatistics order by batchId desc limit ?) AS X order by X.batchId asc", count);
        maps.forEach(map -> {
            List<Map<String, Object>> records = jdbcTemplate.queryForList("select orders `order`,ROUND(money,2) amount,openTime from redpackage where batchId=? order by orders asc ;",map.get("roundId"));
            map.put("items",records);
        });
        return maps;
    }
}
